using AIFSContentManagementSystem.ListExtensions;

using AIFSContentManagementSystem.Criteria.Specifications;

using System;
using System.Collections.Generic;

namespace AIFSContentManagementSystem.Articles
{
    using Messages;

    public sealed class ArticleService : IArticleService
    {
        #region IArticleManager Members

        IParser parser;
        public IParser Parser
        {
            get { return parser; }
        }

        IRepositoryMap repositoryMap;

        public ArticleService(IRepositoryMap RepositoryMap, IParser Parser)
        {
            this.parser = Parser;
            this.repositoryMap = RepositoryMap;
        }

        public GetFilteredArticleListResponse Process(GetFilteredArticleListRequest request)
        {            
            GetFilteredArticleListResponse response = new GetFilteredArticleListResponse();

            if (request.SearchParameter == null)
            {
                response.AddErrorMessage("Search parameter is required for filtering articles");
            }

            if (request.SearchParameter.Program == null)
                response.AddErrorMessage("Program is required");

            if (request.SearchParameter.ArticleType == ArticleType.UNSET)
                response.AddErrorMessage("Article type is required");

            if (response.HasError)
                return response;

            //Step 1 get the article entity
            IArticleRepository articleRepository = this.repositoryMap.Get<IArticleRepository>();
            
            List<Article> articles = articleRepository.GetArticles(request.SearchParameter);

            if (articles != null && articles.Count == 0)
            {
                return response;
            }

            //Create a list of article with event supports. When adding to the filtered list, parse the 
            //content for placeholders
            ListWithEvents<Article> filteredArticles = new ListWithEvents<Article>();
            filteredArticles.OnAddNewItem += new AddNewToListWithEvents<Article>(filteredArticles_OnAddNewItem);                        

            //If request did not have any criterion filter return all articles retrieved
            if (request.Criteria == null)
            {
                filteredArticles.Add(articles);
            }
            else
            {
                foreach (Article article in articles)
                {
                    //Assert the criteria with the requested criteria, if it matches add to the filtered list
                    bool assertResult = false;

                    //Test if article matches the criteria
                    MatchesCriteriaSpecification matchesCriteriaSpec = new MatchesCriteriaSpecification(request.Criteria);
                    assertResult = matchesCriteriaSpec.IsSatisfiedBy(article);

                    //Add to the filtered list. At this point it is ready to be parsed
                    if (assertResult)
                    {
                        filteredArticles.Add(article);
                    }
                }
            }

            response.AddArticle(filteredArticles);
            return response;
        }

        void filteredArticles_OnAddNewItem(object sender, AddNewToListEventArgs<Article> e)
        {
            if (e != null && e.NewObject != null)
            {
                this.parser.Parse(e.NewObject);
            }
        }

        public SaveArticleResponse Process(SaveArticleRequest request)
        {
            SaveArticleResponse response = new SaveArticleResponse();
            IArticleRepository articleRepository = this.repositoryMap.Get<IArticleRepository>();
            articleRepository.Save(request.Article);            

            response.Article = articleRepository.GetArticle(request.Article.ArticleId);
                        
            return response;
        }

        public GetArticleResponse Process(GetArticleRequest request)
        {
            GetArticleResponse response = new GetArticleResponse();

            if (!request.ArticleId.HasValue)
            {
                response.AddErrorMessage("Article Id is required");
                return response;
            }

            IArticleRepository articleRepository = this.repositoryMap.Get<IArticleRepository>();
            
            response.Article = articleRepository.GetArticle(request.ArticleId);
            
            return response;
        }
        #endregion        
    }
}
